package com.brayan.webapp.service.general.i18n;

import java.util.List;

import javax.ejb.Stateful;
import javax.inject.Inject;

import org.apache.log4j.Logger;

import com.brayan.webapp.model.general.i18n.Language;
import com.brayan.webapp.model.general.i18n.Locale;
import com.brayan.webapp.repository.general.country.CountryRepository;
import com.brayan.webapp.repository.general.i18n.LanguageRepository;
import com.brayan.webapp.repository.general.i18n.LocaleRepository;

@Stateful
public class LocaleBean {

	private static Logger LOGGER = Logger.getLogger(LocaleBean.class);

	@Inject
	LocaleRepository localeRepo;
	@Inject
	CountryRepository countryRepo;
	@Inject
	LanguageRepository languageRepo;
	@Inject
	LanguageBean languageService;

	/**
	 * This method must ALWAYS return a language code. Otherwise it's an
	 * exception.
	 * 
	 * @param localeCode
	 * @return
	 */
	public String getLanguageFromLocaleCode(String localeCode) {
		return localeCode.substring(0, 2);
	}

	/**
	 * This method may return an empty string since the localeCode may not
	 * contain a country code.
	 * 
	 * @param localeCode
	 *            e.g. de-CH
	 * @return The country code string returned. e.g. CH. it's always
	 *         uppercased.
	 */
	public String getCountryFromLocaleCode(String localeCode) {
		if(localeCode.length() >=5)
			return localeCode.substring(3, 5).toUpperCase();
		else 
			return null;
	}

	public Locale getLocaleByLocaleCode(String localeCode) {
		String languageCode = getLanguageFromLocaleCode(localeCode);
		String countryCode = getCountryFromLocaleCode(localeCode);
		if (countryCode == null || countryCode.isEmpty())
			return localeRepo.getLocaleByLanguage(languageCode);
		else
			return localeRepo.getLocaleByLanguageAndCountry(languageCode, countryCode);
	}

	public void saveLocale(String localeCode) {
		String languageCode = parseLanguageCodeFromLocaleCode(localeCode);
		String countryCode = parseCountryCodeFromLocaleCode(localeCode);
		
		Locale locale = createLocaleFromLocaleCode(languageCode, countryCode);
		Locale existingLocale = localeRepo.getLocaleByLocaleCode(localeCode);
		if (existingLocale == null)
			localeRepo.saveLocale(locale);
		else
			LOGGER.error("Cannot create a new locale with the locale code (" + localeCode
					+ ") because it already exists (id: " + existingLocale.getId() + ").");
	}
	
	public void saveLocale(String languageCode, String countryCode, String nativeLanguageName){
		
		Locale locale = createLocaleFromLocaleCode(languageCode, countryCode);
		locale.getLanguage().setNativeLanguageName(nativeLanguageName);
		Locale existingLocale = localeRepo.getLocaleByLanguageAndCountry(languageCode, countryCode);
		if (existingLocale == null){
			localeRepo.saveLocale(locale);
			LOGGER.info("Create a new locale with the language code (" + languageCode
				+ ") and country code ("+countryCode+") .");
		}else{
			LOGGER.error("Cannot create a new locale with the language code (" + languageCode
					+ ") and country code ("+countryCode+") because it already exists (id: " + existingLocale.getId() + "). Instead save.");
			localeRepo.updateLocale(locale);
		}
	}

	public Locale createLocaleFromLocaleCode(String languageCode, String countryCode) {

		if (isValidLocaleCode(languageCode, countryCode)) {			
			Locale locale = localeRepo.getLocaleByLanguageAndCountry(languageCode, countryCode);
			if(locale != null)
				return locale;		
			
			
			Language language = languageRepo.getLanguage(languageCode);
			if(language == null){
				languageService.saveLanguage(languageCode);
				language = languageRepo.getLanguage(languageCode);
			}
			if(locale == null)
				locale = new Locale();
			locale.setLanguage(language);
			if (countryCode != null && !countryCode.isEmpty()) {
				locale.setCountry(countryRepo.getCountry(countryCode));
			}
			return locale;
		} else
			LOGGER.error("Cannot save the locale with language code (" + languageCode + ") and country code ("+countryCode+") because it seems to be invalid.");
		return null;
	}

	/**
	 * Tests if the local code e.g. de-CH or de, has the correct format and
	 * length.
	 * 
	 * @param localeCode
	 * @return
	 */
	public boolean isValidLocaleCode(String localeCode) {
		String regex = "(^[a-z]{2}$)|(^[a-z]{2}-[A-Z]{2}$)";
		return localeCode.matches(regex);
	}
	
	public boolean isValidLocaleCode(String languageCode, String countryCode){
		String localeCode = languageCode;
		if(!countryCode.isEmpty())
			localeCode += "-"+countryCode;
		return isValidLocaleCode(localeCode);
	}

	public String parseLanguageCodeFromLocaleCode(String localeCode) {
		if (isValidLocaleCode(localeCode))
			return localeCode.substring(0, 2);
		else {
			LOGGER.error("Cannot parse language code from locale code (" + localeCode + ").");
			return null;
		}
	}

	public String parseCountryCodeFromLocaleCode(String localeCode) {
		if (isValidLocaleCode(localeCode) && localeCode.length() == 5)
			return localeCode.substring(3, 5);
		else {
			LOGGER.error("Cannot parse country code from locale code (" + localeCode + ").");
			return null;
		}
	}

	public List<Locale> getAllLocalesExcept(String localeCode) {		
		return localeRepo.getAllLocalesExcept(localeCode);
	}

}
